using LightSO.ILibrary;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace LightSO.Library.Common
{
    /// <summary>
    /// 对象序列化扩展类
    /// </summary>
    [LightSO.ILibrary.Interface]
    public class SerializerHelper : ISerializerHelper
    {
        /// <summary> 
        /// 将 Stream 转成 byte[] 
        /// </summary> 
        public byte[] ToBytes(Stream stream)
        {
            // 设置当前流的位置为流的开始 
            stream.Seek(0, SeekOrigin.Begin);

            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);

            return bytes;
        }
        private string TimeFormat = "yyyy-MM-dd HH:mm:ss";
        /// <summary>
        /// 尝试将对象转换为指定的类型
        /// </summary>
        /// <typeparam name="T">要转换的目标类型</typeparam>
        /// <param name="value">要转换的对象</param>
        /// <returns>转换后的结果,转换不成功返回类型默认值</returns>
        public T Parse<T>(string value)
        {
            if (Convertor<T>.Parse != null)
            {
                try
                {
                    return Convertor<T>.Parse(value.ToString());
                }
                catch 
                {
                    try
                    {
                        dynamic retval = value;
                        if (typeof(T).Equals(typeof(bool)))
                            retval = Convert.ToInt64(value);

                        return Convert.ChangeType(retval, typeof(T));
                    }
                    catch { }
                }
            }

            return default(T);
        }

        public string ToJson(object obj)
        {
            IsoDateTimeConverter timeFormat = new IsoDateTimeConverter();
            timeFormat.DateTimeFormat = TimeFormat;
            return JsonConvert.SerializeObject(obj, Formatting.Indented, timeFormat);
        }

        public Stream ToStream<T>(T obj)
        {
            var json = ToJson(obj);

            return ToStream(json);
        }

        public Stream ToStream(string text)
        {
            MemoryStream ms = new MemoryStream();
            StreamWriter sw = new StreamWriter(ms);
            sw.AutoFlush = true;
            sw.Write(text);
            ms.Position = 0;
            
            return ms;
        }

        public T FromJson<T>(string json)
        {
            IsoDateTimeConverter timeFormat = new IsoDateTimeConverter();
            timeFormat.DateTimeFormat = TimeFormat;
            return JsonConvert.DeserializeObject<T>(json, timeFormat);
        }

        /// <summary>
        /// 对象间的转换
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public T2 ConvertTo<T1, T2>(T1 value) 
        {
            if (typeof(T1).Equals(typeof(string)))
                return Parse<T2>(value.ToString());

            var result = FromJson<T2>(ToJson(value));

            if (result == null)
                return default(T2);

            return result;
        }


        /// <summary>
        /// XML序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public XDocument ToXDoc<T>(T obj)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));

            var document = new XDocument();
            using (var writer = document.CreateWriter())
            {
                serializer.Serialize(writer, obj);
            }

            return document;
        }

        /// <summary>
        /// XML反序列化
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="document">Xml文档</param>
        /// <returns></returns>
        public T FromXDoc<T>(XDocument document)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));

            try
            {
                using (var reader = document.CreateReader())
                {
                    return (T)serializer.Deserialize(reader);
                }
            }
            catch
            {
                return default(T);
            }
        }


        /// <summary>
        /// XML反序列化
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="xml">Xml字符串</param>
        /// <returns></returns>
        public T FromXml<T>(string xml)
        {
            try
            {
                XDocument document = XDocument.Parse(xml);
                return FromXDoc<T>(document);
            }
            catch 
            {
                return default(T);
            }
        }

        /// <summary>
        /// XML反序列化
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="xmlPath">xml文件路径(物理路径)</param>
        /// <returns></returns>
        public T FromXmlFile<T>(string xmlPath)
        {
            var type = typeof(T);

            using (var stream = new FileStream(xmlPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                try
                {
                    XmlSerializer serializer = new XmlSerializer(type);
                    return (T)serializer.Deserialize(stream);
                }
                catch
                {
                    return default(T);
                }
            }
        }

        /// <summary>
        /// 字符串分隔转数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="values"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public T[] Split<T>(string values, char[] separator = null)
        {
            if (separator == null)
                separator = new char[] { ',' };

            var array = values.Split(separator, StringSplitOptions.RemoveEmptyEntries).Distinct();

            var result = new List<T>();

            foreach (var item in array)
            {
                result.Add(Parse<T>(item));
            }

            return result.ToArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="thisArray"></param>
        /// <returns></returns>
        public IList<int> TrimNull(int?[] thisArray)
        {
            var result = new List<int>();
            foreach (var item in thisArray)
            {
                if (item.HasValue)
                    result.Add(item.Value);
            }
            return result;
        }

        /// <summary>
        /// 类型转换委托
        /// </summary>
        static SerializerHelper()
        {
            Convertor<short>.Parse = short.Parse;
            Convertor<int>.Parse = int.Parse;
            Convertor<long>.Parse = long.Parse;
            Convertor<byte>.Parse = byte.Parse;
            Convertor<ushort>.Parse = ushort.Parse;
            Convertor<uint>.Parse = uint.Parse;
            Convertor<ulong>.Parse = ulong.Parse;
            Convertor<sbyte>.Parse = sbyte.Parse;
            Convertor<float>.Parse = float.Parse;
            Convertor<double>.Parse = double.Parse;
            Convertor<decimal>.Parse = decimal.Parse;
            Convertor<bool>.Parse = bool.Parse;
            Convertor<DateTime>.Parse = DateTime.Parse;
            Convertor<string>.Parse = Convert.ToString;
        }

        /// <summary>
        /// 若值是 null 则使用指定值代换
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="value">原始值</param>
        /// <param name="defaultValue">当值为 null 时用于代换的默认值</param>
        /// <returns>原始值，当原始值不为 null 或 DBbNull，否则使用代换的默认值</returns>
        public T IfNull<T>(T value, T defaultValue)
        {
            if (value == null || Convert.IsDBNull(value))
                return defaultValue;
            else
                return value;
        }

        /// <summary>
        /// 若值是 null 则使用指定值代换
        /// </summary>
        /// <param name="value">原始值</param>
        /// <param name="defaultValue">当值为 null 时用于代换的默认值</param>
        /// <returns>当原始值不为 null 或 DBbNull，返回原始值，否则返回代换的默认值</returns>
        public object IfNull(object value, object defaultValue)
        {
            if (value == null || Convert.IsDBNull(value))
                return defaultValue;
            else
                return value;
        }


        /// <summary>
        /// 若值是 null 则使用指定值代换
        /// </summary>
        /// <typeparam name="TInput">值类型</typeparam>
        /// <typeparam name="TOut">输出值类型</typeparam>
        /// <param name="value">原始值</param>
        /// <param name="defaultValue">当值为 null 时用于代换的默认值</param>
        /// <param name="converter">当值不为空时，对值进行类型转换的转换器。</param>
        /// <returns>当原始值不为 null 或 DBbNull，返回转换后的原始值，否则返回代换的默认值</returns>
        public TOut IfNull<TInput, TOut>(TInput value, TOut defaultValue, Func<TInput, TOut> converter)
        {
            if (value == null || Convert.IsDBNull(value))
                return defaultValue;

            else
            {
                if (converter == null)
                    throw new ArgumentNullException("converter");

                return converter(value);
            }
        }



        /// <summary>
        /// 将对象所有属性转换为对象字典
        /// </summary>
        /// <param name="obj">要转换为对象字典的对象</param>
        /// <returns>对象图</returns>
        public IDictionary<string, string> ToDictionary(object obj)
        {
            if (obj == null)
                return null;

            var dictionary = new Dictionary<string, string>();

            foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(obj))
            {
                var key = property.Name;
                var _value = property.GetValue(obj);

                string value = null;

                if (_value != null)
                    value = _value.ToString();

                dictionary.Add(key, value);
            }

            return dictionary;
        }

        public T Case<T>(object data) where T : IConvertible
        {
            if(data != null)
                return (T)Convert.ChangeType(data, typeof(T));

            return default(T);
        }

        
        private class Convertor<T>
        {
            public static Func<string, T> Parse;
        }
    }
}



